package com.gzc.just.play.last.war.common.model;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Position类的单元测试
 * 
 * @author AI Assistant
 * @version 1.0.0
 * @since 2025-11-25
 */
@DisplayName("位置类测试")
class PositionTest {

    private Position position1;
    private Position position2;
    private Position position3;
    private Position origin;

    @BeforeEach
    void setUp() {
        origin = new Position(); // 默认构造，应为(0,0,0)
        position1 = new Position(10.0, 20.0, 30.0);
        position2 = new Position(40.0, 50.0, 60.0);
        position3 = new Position(10.0, 20.0, 30.0); // 与position1相同
    }

    @Test
    @DisplayName("测试默认构造函数")
    void testDefaultConstructor() {
        assertEquals(0.0, origin.getX(), 0.001);
        assertEquals(0.0, origin.getY(), 0.001);
        assertEquals(0.0, origin.getZ(), 0.001);
    }

    @Test
    @DisplayName("测试三维坐标构造函数")
    void testThreeDimensionalConstructor() {
        assertEquals(10.0, position1.getX(), 0.001);
        assertEquals(20.0, position1.getY(), 0.001);
        assertEquals(30.0, position1.getZ(), 0.001);
    }

    @Test
    @DisplayName("测试二维坐标构造函数")
    void testTwoDimensionalConstructor() {
        Position pos2D = new Position(15.0, 25.0);
        assertEquals(15.0, pos2D.getX(), 0.001);
        assertEquals(25.0, pos2D.getY(), 0.001);
        assertEquals(0.0, pos2D.getZ(), 0.001); // Z应默认为0
    }

    @Test
    @DisplayName("测试坐标设置")
    void testCoordinateSetters() {
        Position pos = new Position();
        
        pos.setX(5.5);
        pos.setY(7.7);
        pos.setZ(9.9);
        
        assertEquals(5.5, pos.getX(), 0.001);
        assertEquals(7.7, pos.getY(), 0.001);
        assertEquals(9.9, pos.getZ(), 0.001);
    }

    @Test
    @DisplayName("测试距离计算")
    void testDistanceCalculation() {
        // 相同点距离为0
        assertEquals(0.0, position1.distanceTo(position1), 0.001);
        assertEquals(0.0, position1.distanceTo(position3), 0.001);
        
        // 测试与原点的距离 (sqrt(10² + 20² + 30²) = sqrt(1400) ≈ 37.417)
        double expectedDistance = Math.sqrt(10.0 * 10.0 + 20.0 * 20.0 + 30.0 * 30.0);
        assertEquals(expectedDistance, position1.distanceTo(origin), 0.001);
        
        // 测试两点之间的距离 (sqrt((40-10)² + (50-20)² + (60-30)²) = sqrt(2700) ≈ 51.962)
        expectedDistance = Math.sqrt(30.0 * 30.0 + 30.0 * 30.0 + 30.0 * 30.0);
        assertEquals(expectedDistance, position1.distanceTo(position2), 0.001);
    }

    @Test
    @DisplayName("测试距离检查")
    void testDistanceCheck() {
        // 相同点
        assertTrue(position1.isWithinDistance(position1, 0.1));
        assertTrue(position1.isWithinDistance(position3, 0.001));
        
        // 测试与原点的距离
        double distanceToOrigin = position1.distanceTo(origin);
        assertTrue(position1.isWithinDistance(origin, distanceToOrigin + 0.1)); // 稍大一点的距离
        assertFalse(position1.isWithinDistance(origin, distanceToOrigin - 0.1)); // 稍小一点的距离
        
        // 测试极端距离
        assertTrue(position1.isWithinDistance(position2, Double.MAX_VALUE));
        assertFalse(position1.isWithinDistance(position2, 0));
    }

    @Test
    @DisplayName("测试方向获取")
    void testDirection() {
        // 测试东向
        Position east = new Position(100.0, 0.0, 0.0);
        assertEquals("East", east.getDirection());
        
        // 测试西向
        Position west = new Position(-100.0, 0.0, 0.0);
        assertEquals("West", west.getDirection());
        
        // 测试北向
        Position north = new Position(0.0, 100.0, 0.0);
        assertEquals("North", north.getDirection());
        
        // 测试南向
        Position south = new Position(0.0, -100.0, 0.0);
        assertEquals("South", south.getDirection());
        
        // 测试X轴绝对值更大
        Position northeast = new Position(100.0, 50.0, 0.0);
        assertEquals("East", northeast.getDirection());
        
        // 测试Y轴绝对值更大
        Position northwest = new Position(50.0, 100.0, 0.0);
        assertEquals("North", northwest.getDirection());
        
        // 测试原点（当X和Y相同时）
        Position diagonal = new Position(100.0, 100.0, 0.0);
        assertEquals("North", diagonal.getDirection()); // Y绝对值相等时返回North
    }

    @Test
    @DisplayName("测试equals方法")
    void testEquals() {
        // 测试自相等
        assertTrue(position1.equals(position1));
        
        // 测试相同值的不同对象
        assertTrue(position1.equals(position3));
        
        // 测试不同值
        assertFalse(position1.equals(position2));
        
        // 测试null
        assertFalse(position1.equals(null));
        
        // 测试不同类型
        assertFalse(position1.equals("not a position"));
    }

    @Test
    @DisplayName("测试hashCode方法")
    void testHashCode() {
        // 相等对象应有相同的hashCode
        assertEquals(position1.hashCode(), position3.hashCode());
        
        // 不相等对象通常应有不同的hashCode（不绝对保证）
        assertNotEquals(position1.hashCode(), position2.hashCode());
        
        // 验证原点的hashCode
        Position anotherOrigin = new Position();
        assertEquals(origin.hashCode(), anotherOrigin.hashCode());
    }

    @Test
    @DisplayName("测试toString方法")
    void testToString() {
        String posString = position1.toString();
        assertTrue(posString.contains("10.00"));
        assertTrue(posString.contains("20.00"));
        assertTrue(posString.contains("30.00"));
        assertTrue(posString.contains("("));
        assertTrue(posString.contains(")"));
        assertTrue(posString.contains(","));
    }

    @Test
    @DisplayName("测试特殊情况")
    void testSpecialCases() {
        // 测试极大值
        Position large = new Position(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
        assertEquals(Double.MAX_VALUE, large.getX(), 0.001);
        assertEquals(Double.MAX_VALUE, large.getY(), 0.001);
        assertEquals(Double.MAX_VALUE, large.getZ(), 0.001);
        
        // 测试极小值
        Position small = new Position(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
        assertEquals(Double.MIN_VALUE, small.getX(), 0.001);
        assertEquals(Double.MIN_VALUE, small.getY(), 0.001);
        assertEquals(Double.MIN_VALUE, small.getZ(), 0.001);
        
        // 测试负值
        Position negative = new Position(-10.5, -20.5, -30.5);
        assertEquals(-10.5, negative.getX(), 0.001);
        assertEquals(-20.5, negative.getY(), 0.001);
        assertEquals(-30.5, negative.getZ(), 0.001);
        
        // 测试NaN
        Position nan = new Position(Double.NaN, 0.0, 0.0);
        assertTrue(Double.isNaN(nan.getX()));
        assertEquals(0.0, nan.getY(), 0.001);
        assertEquals(0.0, nan.getZ(), 0.001);
        
        // 测试无穷大
        Position infinite = new Position(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0);
        assertTrue(Double.isInfinite(infinite.getX()));
        assertTrue(Double.isInfinite(infinite.getY()));
        assertEquals(0.0, infinite.getZ(), 0.001);
    }

    @Test
    @DisplayName("测试距离计算的边界情况")
    void testDistanceEdgeCases() {
        // 零坐标
        Position zero = new Position(0.0, 0.0, 0.0);
        assertEquals(0.0, zero.distanceTo(zero), 0.001);
        
        // 极大值距离（可能会有溢出，但仍应有返回值）
        Position max1 = new Position(Double.MAX_VALUE, 0.0, 0.0);
        Position max2 = new Position(Double.MIN_VALUE, 0.0, 0.0);
        // 由于极大值计算可能溢出，我们不检查具体值，只确保方法不抛异常
        assertDoesNotThrow(() -> max1.distanceTo(max2));
        
        // 无穷值距离
        Position inf1 = new Position(Double.POSITIVE_INFINITY, 0.0, 0.0);
        Position inf2 = new Position(0.0, Double.NEGATIVE_INFINITY, 0.0);
        // 无穷值距离应为无穷大
        assertTrue(Double.isInfinite(inf1.distanceTo(inf2)));
    }

    @Test
    @DisplayName("测试复杂数学场景")
    void testComplexMathScenarios() {
        // 构造一个3-4-5直角三角形
        Position rightTriangle = new Position(3.0, 4.0, 0.0);
        assertEquals(5.0, rightTriangle.distanceTo(origin), 0.001);
        
        // 构造一个5-12-13直角三角形
        Position largerTriangle = new Position(5.0, 12.0, 0.0);
        assertEquals(13.0, largerTriangle.distanceTo(origin), 0.001);
        
        // 构造一个立方体对角线 (sqrt(1² + 1² + 1²) = sqrt(3) ≈ 1.732)
        Position unitCube = new Position(1.0, 1.0, 1.0);
        assertEquals(Math.sqrt(3.0), unitCube.distanceTo(origin), 0.001);
        
        // 测试单位圆上的点（距离应为1）
        double angle = Math.PI / 4; // 45度
        Position unitCircle = new Position(Math.cos(angle), Math.sin(angle), 0.0);
        assertEquals(1.0, unitCircle.distanceTo(origin), 0.001);
    }
}